#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"

using namespace std;

// 对抢票进行改进
#define NUM 4

// 定义一个全局（静态）锁
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

class threadData
{
public:
    threadData(int number /*, pthread_mutex_t *mutex*/)
    {
        threadname = "thread-" + to_string(number);
        //  lock = mutex;
    }

public:
    string threadname;
    // pthread_mutex_t *lock;
};

int tickets = 1000; // 模拟多线程抢票

// void *getTicket(void *args)
// {
//     threadData *td = static_cast<threadData *>(args);
//     const char *name = td->threadname.c_str();
//     while (true)
//     {
//         // 加锁
//         //线程对于锁的竞争能力可能会不同
//        //pthread_mutex_lock(td->lock); // 申请成功，才能执行，不成功，阻塞等待
//         pthread_mutex_lock(&lock);
//         // 临界区--临界资源
//         if (tickets > 0)
//         {
//             usleep(1000);
//             printf("who=%s, get a ticket: %d\n", name, tickets);
//             tickets--;
//             //解锁
//             // pthread_mutex_unlock(td->lock);
//             pthread_mutex_lock(&lock);
//         }
//         else
//         {
//             //解锁
//             // pthread_mutex_unlock(td->lock);
//             pthread_mutex_lock(&lock);
//             break;
//         }
//         usleep(13);
//     }
//     printf("%s ...quit\n", name);
//     return nullptr;
// }

void *getTicket(void *args)
{
    threadData *td = static_cast<threadData *>(args);
    const char *name = td->threadname.c_str();
    while (true)
    {
        {
            LockGuard lockguard(&lock);
            if (tickets > 0)
            {
                usleep(1000);
                printf("who=%s, get a ticket: %d\n", name, tickets);
                tickets--;
            }
            else
            {
                break;
            }
        }
        usleep(13);
    }
    printf("%s ...quit\n", name);
    return nullptr;
}

int main()
{
    // 定义一个锁
    pthread_mutex_t lock;
    // 初始化锁
    pthread_mutex_init(&lock, nullptr);

    vector<pthread_t> tids;            // 保存的tids数据
    vector<threadData *> thread_datas; // 保存的是参数数据

    for (int i = 0; i <= NUM; i++)
    {
        pthread_t tid; // 申明一个线程tid
        // 把锁传给每一个线程
        threadData *td = new threadData(i /*, &lock*/);
        thread_datas.push_back(td);
        pthread_create(&tid, nullptr, getTicket, thread_datas[i - 1]);
        tids.push_back(tid);
    }

    for (auto thread : tids)
    {
        pthread_join(thread, nullptr);
    }
    for (auto td : thread_datas)
    {
        delete td;
    }

    // 对锁进行释放
    // pthread_mutex_destroy(td->lock);
    return 0;
}

// #define NUM 4

// int tickets = 1000; // 模拟多线程抢票

// class threadData
// {
// public:
//     threadData(int number)
//     {
//         threadname = "thread-" + to_string(number);
//     }

// public:
//     string threadname;
// };

// void *getTicket(void *args)
// {
//     threadData *td = static_cast<threadData *>(args);
//     const char *name = td->threadname.c_str();
//     while (true)
//     {
//         // printf("%s is runing..., cnt:%d\n", td->threadname.c_str(),cnt--);
//         // sleep(1);

//         if (tickets > 0)
//         {
//             usleep(1000);
//             printf("who=%s, get a ticket: %d\n", name, tickets);
//             tickets--;
//         }
//         else
//             break;

//     }
//     printf("%s ...quit\n", name);
//     return nullptr;
// }

// int main()
// {
//     vector<pthread_t> tids;            // 保存的tids数据
//     vector<threadData *> thread_datas; // 保存的是参数数据

//     for (int i = 0; i <= NUM; i++)
//     {
//         pthread_t tid; // 申明一个线程tid

//         threadData *td = new threadData(i);
//         thread_datas.push_back(td);
//         pthread_create(&tid, nullptr, getTicket, thread_datas[i - 1]);
//         tids.push_back(tid);
//     }

//     for (auto thread : tids)
//     {
//         pthread_join(thread, nullptr);
//     }
//     for (auto td : thread_datas)
//     {
//         delete td;
//     }
//     return 0;
// }
